package com.link.gateway.base.urlinfo.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.link.gateway.base.urlinfo.model.UrlInfo;
import com.link.gateway.core.comproperty.RunProperties;
import com.link.gateway.core.comproperty.TokenConstants;
import com.link.gateway.core.redis.redisclient.LinkRedisClient;
import com.link.gateway.core.utils.RedisUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import redis.clients.jedis.ScanResult;

import java.util.*;

/**
 * @author huanglongjian
 * @date 2019年07月23日
 */
@Service
public class UrlInfoServiceImpl implements UrlInfoService {
    private static final Logger logger = LogManager.getLogger(UrlInfoServiceImpl.class);

    /**
     * 加载默认的可访问地址到缓存中。同时更新全局变量的版本号
     * （因为是把默认可访问的地址放到全局变量中的，所以在负载时候会出现不统一的问题。通过把版本号存入redis中，实现服务间的统一）
     *
     * @author huanglongjian
     * @date 2019-02-25 17:11
     */
    @Override
    public void loadUrlToRedis() throws Exception {
        LinkRedisClient jedis = RedisUtil.getJedis();
        try {
            //首先设置缓存
            setDefUrlCache();
        } catch (Exception e) {
            logger.error(e);
            throw e;
        } finally {
            RedisUtil.returnResource(jedis);
        }
    }

    /**
     * @author HuangLJ
     * @date 2019-02-25 17:10
     * @throws Exception 报错
     * 把默认的url信息写入到全局变量里面去
     */
    @Override
    public void setDefUrlCache() throws Exception {
        LinkRedisClient linkRedisClient = null;
        try {
            linkRedisClient = RedisUtil.getJedis();

            //获取得到所有的map信息
            Map<String, String> mapAll = getMapByRedisHKey(TokenConstants.ALL_URL_REDIS_KEY);

            //默认可访问的map
            Map<String, String> mapDefUrl = new HashMap<>(16);

            //所有范围的map
            Map<String, String> mapScope = new HashMap<>(16);

            //所有url列表
            Map<String, UrlInfo> mapUrlDetail = new HashMap<>(30);

            for (Map.Entry<String, String> entry : mapAll.entrySet()) {
                JSONObject jsonObjUrlInfo = JSON.parseObject(entry.getValue());
                UrlInfo urlInfo = getUrlInfoFromJsonObj(jsonObjUrlInfo);

                //设置默认可访问map
                putDefUrlMap(urlInfo, mapDefUrl);

                //把范围放入到map中
                mapScope.put(urlInfo.getUrl(), urlInfo.getScopePermission());

                //把所有接口信息都写到一个变量
                mapUrlDetail.put(urlInfo.getUrl(), urlInfo);

            }

            //把url放到静态变量里面去
            RunProperties.setDefUrl(mapDefUrl);

            //把所有接口的范围信息都写入到一个变量里面来
            RunProperties.setAllUrlScope(mapScope);

            //把所有接口详细信息都写到一个变量
            RunProperties.setAllUrlDetail(mapUrlDetail);

        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new Exception(e);
        } finally {
            RedisUtil.returnResource(linkRedisClient);
        }
    }

    /**
     * @author HuangLJ
     * @date 2019-07-28 11:22
     * @param key redis中的key
     * @throws Exception 报错
     * 通过一个key，获取redis中的map信息。
     */
    private Map<String, String> getMapByRedisHKey(String key) throws Exception {
        LinkRedisClient linkRedisClient = null;
        try {
            linkRedisClient = RedisUtil.getJedis();
            Map<String, String> map = new HashMap<>(16);
            //设置游标为0
            String cursor = "0";
            do {
                //遍历游标
                ScanResult<Map.Entry<String, String>> retScop = linkRedisClient.hscan(key, cursor);
                for (Map.Entry<String, String> mapScop : retScop.getResult()) {
                    //把得到的信息拆出来，放入到map里面去
                    map.put(mapScop.getKey(), mapScop.getValue());
                }
                //把返回的游标设置到值里面去
                cursor = retScop.getStringCursor();

                //游标不为0 则继续遍历
            }
            while (Integer.parseInt(cursor) != 0);

            return map;
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new Exception(e);
        } finally {
            RedisUtil.returnResource(linkRedisClient);
        }
    }

    /**
     * @author HuangLJ
     * @date 2019-07-25 21:20
     * 通过传入的JSONObject 返回其对象
     */
    private UrlInfo getUrlInfoFromJsonObj(JSONObject jsonObjectUrlInfo) throws Exception {
        UrlInfo urlInfo = new UrlInfo();
        urlInfo.setComments(jsonObjectUrlInfo.getString("comments"));
        urlInfo.setDefaultAccessFlag(jsonObjectUrlInfo.getString("url"));
        urlInfo.setDelFlag(jsonObjectUrlInfo.getString("delFlag"));
        urlInfo.setInsertFlag(jsonObjectUrlInfo.getString("insertFlag"));
        urlInfo.setName(jsonObjectUrlInfo.getString("name"));
        urlInfo.setType(jsonObjectUrlInfo.getString("type"));
        urlInfo.setScopePermission(jsonObjectUrlInfo.getString("scopePermission"));
        urlInfo.setSelectFlag(jsonObjectUrlInfo.getString("selectFlag"));
        urlInfo.setUpdateFlag(jsonObjectUrlInfo.getString("updateFlag"));
        urlInfo.setUrl(jsonObjectUrlInfo.getString("url"));
        urlInfo.setDefaultAccessFlag(jsonObjectUrlInfo.getString("defaultAccessFlag"));
        urlInfo.setInputParaFlag(jsonObjectUrlInfo.getString("inputParaFlag"));
        urlInfo.setOutParaFlag(jsonObjectUrlInfo.getString("outParaFlag"));
        urlInfo.setLogKeepTime(jsonObjectUrlInfo.getInteger("logKeepTime"));
        urlInfo.setBlackList(jsonObjectUrlInfo.getString("blackIps"));
        urlInfo.setWhiteList(jsonObjectUrlInfo.getString("whiteIps"));
        return urlInfo;
    }

    /**
     * @author HuangLJ
     * @date 2019-07-28 12:10
     * @param urlInfo 当前的url对象
     * @param mapDefUrl 需要设置的map信息
     * 判断当前的url对象是否要放入到默认可访问的map中去
     */
    private void putDefUrlMap(UrlInfo urlInfo , Map<String, String> mapDefUrl) {
        //获取得到默认可访问和已经被删除了的URL放入到
        if (!"Y".equals(urlInfo.getDelFlag()) && "Y".equals(urlInfo.getDefaultAccessFlag())) {
            //不是删除，但是默认是可以访问的URL
            mapDefUrl.put(urlInfo.getUrl(), "Y");
        } else if ("Y".equals(urlInfo.getDelFlag())) {
            //删除的url
            mapDefUrl.put(urlInfo.getUrl(), "N");
        }
    }

}
